﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.WindowsAPICodePack.Shell;

namespace ArchiveLink
{
    internal class DirectoryLinker
    {
        static int SYMLINK_FLAG_DIRECTORY = 1;
        static int SYMLINK_FLAG_FILE = 0;

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
        private static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, int dwFlags);


        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool GetVolumeNameForVolumeMountPoint(string
            lpszVolumeMountPoint, [Out] StringBuilder lpszVolumeName,
            uint cchBufferLength);

        [DllImport("kernel32.dll")]
        static extern bool DeleteVolumeMountPoint(string lpszVolumeMountPoint);

        [DllImport("kernel32.dll")]
        static extern bool SetVolumeMountPoint(string lpszVolumeMountPoint,
            string lpszVolumeName);

        const int MAX_PATH = 260;

        public static void CreateDirLink(DirectoryInfo source, string linkPath)
        {
            if (Directory.Exists(linkPath))
            {
                ShellObject obj = ShellObject.FromParsingName(linkPath);
                if (obj.IsLink)
                {
                    if (((ShellLink)obj).TargetLocation != source.FullName)
                    {
                        Directory.Delete(linkPath);
                        if (!CreateSymbolicLink(linkPath, source.FullName, SYMLINK_FLAG_DIRECTORY))
                        {
                            //throw new Exception("Cannot create link");
                        }
                    }
                }
                else
                {
                    //throw new Exception("TODO: no link");
                }
            }
            else
            {
                if (!CreateSymbolicLink(linkPath, source.FullName, SYMLINK_FLAG_DIRECTORY))
                {
                    //throw new Exception("Cannot create link");
                }
            }
        }



        public static void CreateFileLink(FileInfo source, string linkPath)
        {
            if (File.Exists(linkPath))
            {
                ShellObject obj = ShellObject.FromParsingName(linkPath);
                if (obj.IsLink)
                {
                    if (((ShellLink)obj).TargetLocation != source.FullName)
                    {
                        File.Delete(linkPath);
                        if (!CreateSymbolicLink(linkPath, source.FullName, SYMLINK_FLAG_FILE))
                        {
                            //throw new Exception("Cannot create link");
                        }
                    }
                }
                else
                {
                    //throw new Exception("TODO: no link");
                }
            }
            else
            {
                if (!CreateSymbolicLink(linkPath, source.FullName, SYMLINK_FLAG_FILE))
                {
                    //throw new Exception("Cannot create link");
                }
            }
        }


        public static void CreateMountPoint(string driveLetter, string targetDir)
        {
            var di = new DirectoryInfo(targetDir);
            if (!di.Exists)
            {
                di.Create();
            }

            StringBuilder volume = new StringBuilder(MAX_PATH);
            if (!GetVolumeNameForVolumeMountPoint(driveLetter, volume, (uint)MAX_PATH))
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());

            if (!targetDir.EndsWith("\\"))
            {
                targetDir += "\\";
            }

            if (!SetVolumeMountPoint(targetDir, volume.ToString()))
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
        }

        private void DeleteMountPoint(string mountPoint)
        {
            if (!DeleteVolumeMountPoint(mountPoint))
            {
                //   Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
            }
        }

    }
}
